#include "Tkgles.h"
#ifndef __Context_h_
#include "Context.h"
#endif

/*==================================================================================================
*	NOTE: Matrix form : In OpenGL ES's calculation, matrices form is represented as:
*	
*	a11	a21	a31	a41
*
*	a12	a22	a32	a42
*	
*	a13	a23	a33	a43
*	
*	a14	a24	a34	a44
*
*	When using the normal format matrices, remember to transform it
==================================================================================================*/


EXPORT void MatrixInit(){

	Context * context = getContext();
	INT i;

	if (context) {
		context->Matrix.IdentityMatrix[0] = 1.0f;
		context->Matrix.IdentityMatrix[1] = 0.0f;
		context->Matrix.IdentityMatrix[2] = 0.0f;
		context->Matrix.IdentityMatrix[3] = 0.0f;

		context->Matrix.IdentityMatrix[4] = 0.0f;
		context->Matrix.IdentityMatrix[5] = 1.0f;
		context->Matrix.IdentityMatrix[6] = 0.0f;
		context->Matrix.IdentityMatrix[7] = 0.0f;

		context->Matrix.IdentityMatrix[8] = 0.0f;
		context->Matrix.IdentityMatrix[9] = 0.0f;
		context->Matrix.IdentityMatrix[10] = 1.0f;
		context->Matrix.IdentityMatrix[11] = 0.0f;

		context->Matrix.IdentityMatrix[12] = 0.0f;
		context->Matrix.IdentityMatrix[13] = 0.0f;
		context->Matrix.IdentityMatrix[14] = 0.0f;
		context->Matrix.IdentityMatrix[15] = 1.0f;
		
		context->Matrix.ModelViewStackPointer = 0;
		context->Matrix.ProjectionStackPointer = 0;
		for (i = 0; i < GL_MAX_TEXTURE_UNITS; i++){
			context->Matrix.TextureStackPointer[i] = 0;
		}

		context->Matrix.pCurrentMatrix = &(context->Matrix.ModelViewStack[context->Matrix.ModelViewStackPointer]);
		MatrixImport((GLfloat *)(&(context->Matrix.IdentityMatrix)));
		context->Matrix.pCurrentMatrix = &(context->Matrix.ProjectionStack[context->Matrix.ProjectionStackPointer]);
		MatrixImport((GLfloat *)(&(context->Matrix.IdentityMatrix)));
		//printf("preparing import texture matrix\n");
		for (i = 0; i < GL_MAX_TEXTURE_UNITS; i++){
			context->Matrix.pCurrentMatrix = &(context->Matrix.TextureStack[i][context->Matrix.TextureStackPointer[i]]);
			MatrixImport((GLfloat *)(&(context->Matrix.IdentityMatrix)));
		}
		
		context->Matrix.pCurrentMatrix = &(context->Matrix.ModelViewStack[context->Matrix.ModelViewStackPointer]);
	}
}
EXPORT void MatrixImport(GLfloat * m) {

	Context * context = getContext();

	if (context){
		context->Matrix.pCurrentMatrix[0]._11 = m[0];
		context->Matrix.pCurrentMatrix[0]._12 = m[1];
		context->Matrix.pCurrentMatrix[0]._13 = m[2];
		context->Matrix.pCurrentMatrix[0]._14 = m[3];
		context->Matrix.pCurrentMatrix[0]._21 = m[4];
		context->Matrix.pCurrentMatrix[0]._22 = m[5];
		context->Matrix.pCurrentMatrix[0]._23 = m[6];
		context->Matrix.pCurrentMatrix[0]._24 = m[7];
		context->Matrix.pCurrentMatrix[0]._31 = m[8];
		context->Matrix.pCurrentMatrix[0]._32 = m[9];
		context->Matrix.pCurrentMatrix[0]._33 = m[10];
		context->Matrix.pCurrentMatrix[0]._34 = m[11];
		context->Matrix.pCurrentMatrix[0]._41 = m[12];
		context->Matrix.pCurrentMatrix[0]._42 = m[13];
		context->Matrix.pCurrentMatrix[0]._43 = m[14];
		context->Matrix.pCurrentMatrix[0]._44 = m[15];
	}
	//printf("Matrix imported \n");
}

EXPORT void MatrixImportM(GLfloat * m) {

	Context * context = getContext();
	GLfloat temp[16];

	if (context){
		temp[0] = context->Matrix.pCurrentMatrix[0]._11*m[0] + context->Matrix.pCurrentMatrix[0]._21*m[1] + 
						context->Matrix.pCurrentMatrix[0]._31*m[2] + context->Matrix.pCurrentMatrix[0]._41*m[3];
		temp[1] = context->Matrix.pCurrentMatrix[0]._12*m[0] + context->Matrix.pCurrentMatrix[0]._22*m[1] +
						context->Matrix.pCurrentMatrix[0]._32*m[2] + context->Matrix.pCurrentMatrix[0]._42*m[3];
		temp[2] = context->Matrix.pCurrentMatrix[0]._13*m[0] + context->Matrix.pCurrentMatrix[0]._23*m[1] +
						context->Matrix.pCurrentMatrix[0]._33*m[2] + context->Matrix.pCurrentMatrix[0]._43*m[3];
		temp[3] = context->Matrix.pCurrentMatrix[0]._14*m[0] + context->Matrix.pCurrentMatrix[0]._24*m[1] +
						context->Matrix.pCurrentMatrix[0]._34*m[2] + context->Matrix.pCurrentMatrix[0]._44*m[3];

		temp[4] = context->Matrix.pCurrentMatrix[0]._11*m[4] + context->Matrix.pCurrentMatrix[0]._21*m[5] + 
						context->Matrix.pCurrentMatrix[0]._31*m[6] + context->Matrix.pCurrentMatrix[0]._41*m[7];
		temp[5] = context->Matrix.pCurrentMatrix[0]._12*m[4] + context->Matrix.pCurrentMatrix[0]._22*m[5] +
						context->Matrix.pCurrentMatrix[0]._32*m[6] + context->Matrix.pCurrentMatrix[0]._42*m[7];
		temp[6] = context->Matrix.pCurrentMatrix[0]._13*m[4] + context->Matrix.pCurrentMatrix[0]._23*m[5] +
						context->Matrix.pCurrentMatrix[0]._33*m[6] + context->Matrix.pCurrentMatrix[0]._43*m[7];
		temp[7] = context->Matrix.pCurrentMatrix[0]._14*m[4] + context->Matrix.pCurrentMatrix[0]._24*m[5] +
						context->Matrix.pCurrentMatrix[0]._34*m[6] + context->Matrix.pCurrentMatrix[0]._44*m[7];

		temp[8] = context->Matrix.pCurrentMatrix[0]._11*m[8] + context->Matrix.pCurrentMatrix[0]._21*m[9] + 
						context->Matrix.pCurrentMatrix[0]._31*m[10] + context->Matrix.pCurrentMatrix[0]._41*m[11];
		temp[9] = context->Matrix.pCurrentMatrix[0]._12*m[8] + context->Matrix.pCurrentMatrix[0]._22*m[9] +
						context->Matrix.pCurrentMatrix[0]._32*m[10] + context->Matrix.pCurrentMatrix[0]._42*m[11];
		temp[10] = context->Matrix.pCurrentMatrix[0]._13*m[8] + context->Matrix.pCurrentMatrix[0]._23*m[9] +
						context->Matrix.pCurrentMatrix[0]._33*m[10] + context->Matrix.pCurrentMatrix[0]._43*m[11];
		temp[11] = context->Matrix.pCurrentMatrix[0]._14*m[8] + context->Matrix.pCurrentMatrix[0]._24*m[9] +
						context->Matrix.pCurrentMatrix[0]._34*m[10] + context->Matrix.pCurrentMatrix[0]._44*m[11];

		temp[12] = context->Matrix.pCurrentMatrix[0]._11*m[12] + context->Matrix.pCurrentMatrix[0]._21*m[13] + 
						context->Matrix.pCurrentMatrix[0]._31*m[14] + context->Matrix.pCurrentMatrix[0]._41*m[15];
		temp[13] = context->Matrix.pCurrentMatrix[0]._12*m[12] + context->Matrix.pCurrentMatrix[0]._22*m[13] +
						context->Matrix.pCurrentMatrix[0]._32*m[14] + context->Matrix.pCurrentMatrix[0]._42*m[15];
		temp[14] = context->Matrix.pCurrentMatrix[0]._13*m[12] + context->Matrix.pCurrentMatrix[0]._23*m[13] +
						context->Matrix.pCurrentMatrix[0]._33*m[14] + context->Matrix.pCurrentMatrix[0]._43*m[15];
		temp[15] = context->Matrix.pCurrentMatrix[0]._14*m[12] + context->Matrix.pCurrentMatrix[0]._24*m[13] +
						context->Matrix.pCurrentMatrix[0]._34*m[14] + context->Matrix.pCurrentMatrix[0]._44*m[15];

		MatrixImport(temp);
	}
}

/*==================================================================================================
*	NAME: MatrixMultipy
*
*	DESCRIPTIONS:
*	Multiply 4x4 matrix in 'matrix' parameter to 4x1 matrix in 'src' and save result to 'des' which is
*	a 4x1 matrix 
*
*	PARAMETER:
*		-
*	RETURNS:
*		-
==================================================================================================*/
EXPORT void MatrixMultiply(Matrix4x4 * matrix, Vect4D * src,Vect4D * des){
	//printf("x: %f, y: %f, z: %f, t: %f\n", src[0].x, src[0].y,src[0].z,src[0].t);	
	des[0].x = matrix[0]._11 * src[0].x + 
				  matrix[0]._21 * src[0].y +
				  matrix[0]._31 * src[0].z +
				  matrix[0]._41 * src[0].t;
	
	des[0].y = matrix[0]._12 * src[0].x +
				  matrix[0]._22 * src[0].y +
				  matrix[0]._32 * src[0].z +
				  matrix[0]._42 * src[0].t;

	des[0].z = matrix[0]._13 * src[0].x +
				  matrix[0]._23 * src[0].y +
				  matrix[0]._33 * src[0].z +
				  matrix[0]._43 * src[0].t;

	des[0].t = matrix[0]._14 * src[0].x +
				  matrix[0]._24 * src[0].y +
				  matrix[0]._34 * src[0].z +
				  matrix[0]._44 * src[0].t;
	//printf("x: %f, y: %f, z: %f, t: %f\n", des[0].x, des[0].y,des[0].z,des[0].t);
}

EXPORT void PerspectiveDevise(Vect4D * src, Vect3D * des){
	
	des[0].x = src[0].x / src[0].t;
	des[0].y = src[0].y / src[0].t;
	des[0].z = src[0].z / src[0].t;
}

EXPORT void ViewportTransform(Vect3D * src, Vect3D * des){

	Context * context = getContext();

	if (context){
        //printf("Z before: %f\n",src[0].z);
		//printf("Viewport : %d, %d, %d, %d\n",context->ViewPort.px, context->ViewPort.py,context->ViewPort.ox, context->ViewPort.oy);
		des[0].x = (GLfloat)(context->ViewPort.px)/2 * src[0].x + (GLfloat)context->ViewPort.ox;
		des[0].y = (GLfloat)(context->ViewPort.py)/2 * src[0].y + (GLfloat)context->ViewPort.oy;
		des[0].z = (context->DepthRange.zFar - context->DepthRange.zNear)/2 * src[0].z + 
						(context->DepthRange.zFar + context->DepthRange.zNear)/2;
        //printf("Z after: %f\n",des[0].z);
    }
}

